using System;
using System.Collections;
using System.Collections.Generic;
using System.Html;
using System.Runtime.CompilerServices;
using Awaiter;
using jQueryApi;

namespace Nsb.Classes
{
    [IgnoreNamespace]
    public abstract class Cluster : DomElement
    {
        protected static readonly Dictionary<string, Truple> Truples = new Dictionary<string, Truple>();
        protected static readonly Dictionary<string, jQueryObject> Elements = new Dictionary<string, jQueryObject>();
        public static jQueryObject HiderElement;
        private static int _hiderCount;
        private static readonly bool SpinnerTgB = AddSpinner();
        private static int _spinnerCnt;
        [PreserveCase, PreserveName] public string ClassName;

        protected bool TryLoadProperties(object properties)
        {
            if (Type.GetScriptType(properties) == "object")
            {
                if (Script.IsValue(properties))
                    foreach (KeyValuePair<string, object> kv in (Dictionary) properties)
                    {
                        try
                        {
                            // ReSharper disable SuspiciousTypeConversion.Global
                            Dictionary d = (Dictionary) (object) this;
                            // ReSharper restore SuspiciousTypeConversion.Global
                            d[kv.Key] = kv.Value;
                        }
                        catch (Exception)
                        {
                            //throw new Exception("Undefined property[" + kv.Key + "]");
                        }
                    }
                return true;
            }
            return false;
        }

        public static Dictionary GlassCss(string bkgnd)
        {
            return
                new Dictionary(
                    "position", "absolute",
                    "top", 0,
                    "left", 0,
                    "width", DocumentWidth(),
                    "height", DocumentHeight(),
                    "margin", 0,
                    "padding", 0,
                    "background", bkgnd
                    );
        }

        [AlternateSignature]
        public extern void HiderAw(Await awp, bool hiderOn);

        public void HiderAw(Await awp, bool hiderOn, double opacity)
        {
            Hider(hiderOn, opacity);
            if (Element != null)
            {
                if (hiderOn)
                    Element.AddClass("AboveHider");
                else
                    Element.RemoveClass("AboveHider");
            }
            awp.Done();
        }

        [AlternateSignature]
        public static extern jQueryObject Hider(bool hiderOn);

        public static jQueryObject Hider(bool hiderOn, double opacity)
        {
            opacity = Script.Value(opacity, 0.55);
            if (hiderOn)
            {
                if (_hiderCount++ > 0)
                    return jQuery.Select("#HiderSurface");
                HiderElement = jQuery.FromHtml("<div id='HiderSurface'/>")
                    .AppendTo(Document.Body)
                    .CSS(GlassCss("#000"))
                    .CSS(new Dictionary("opacity", opacity))
                    .AddClass("HiderZee")
                    .Show()
                    // Swallow all mouse events on hider
                    ;
                HiderElement.Plugin<Jewl>().SwallowAllMouseEvents();
                return HiderElement;
            }
            if (--_hiderCount > 0)
                return jQuery.Select("#HiderSurface");
            jQuery.Select(".HiderSpinner").Remove();
            jQueryObject el = HiderElement;
            HiderElement = null;
            if (el != null)
            {
                FileBlobBase.SvCnt++;
                el.FadeOut(200,
                           delegate
                           {
                               jQuery.Select("#HiderSurface").Unbind(".swallowed").Remove();
                               FileBlobBase.SvCnt--;
                           });
            }
            return null;
        }

        private static bool AddSpinner()
        {
            jQuery.Document.Bind("Spinner", SpinnerTg);
            return !SpinnerTgB;
        }

        [AlternateSignature]
        public static extern void SpinnerTg(jQueryEvent e);

        public static void SpinnerTg(jQueryEvent e, bool @on, double opacity)
        {
            //Inform.Debug("SpinnerTg({0})", @on);
            if (@on)
            {
                if (_spinnerCnt++ > 0)
                    return;
                Hider(true, Type.GetScriptType(opacity) == "number" ? opacity : .8);
                jQuery.FromHtml("<div id='HiderSpinner' class='AboveHider'><img src='" + Uri.Img("Common/spinner30.gif") + "'></div>")
                    .AppendTo(Document.Body)
                    .Plugin<Jewl>().Position(new Dictionary("my", "center", "at", "center", "of", Window.Self))
                    ;
            }
            else if (--_spinnerCnt <= 0)
            {
                _spinnerCnt = 0;
                Hider(false);
                jQuery.Select("#HiderSpinner").Remove();
            }
        }

        [AlternateSignature]
        public static extern void Spinner(bool @on);

        public static void Spinner(bool @on, double opacity)
        {
            SpinnerTg(null, @on, opacity);
        }

        public static jQueryObject Glass(jQueryEventHandler clickFn)
        {
            GlassOff();
            jQueryObject glass = jQuery.FromHtml("<div class='VirtualGlass'/>");
            glass
                .AppendTo(Document.Body)
                .CSS(GlassCss("transparent"))
                .AddClass("GlassZee")
                .MouseDown(
                    delegate(jQueryEvent e)
                    {
                        if (e.Target == glass[0])
                            GlassOff();
                        CancelEvent(e);
                    });
            glass.Data("GlassOffFn", clickFn);
            jQuery.Window
                .Unbind("resize.Glass")
                .Bind("resize.Glass",
                      delegate
                      {
                          jQueryObject vg = jQuery.Select("body > .VirtualGlass");
                          jQueryEventHandler fn = (jQueryEventHandler) vg.GetDataValue("GlassOffFn");
                          vg.RemoveData("GlassOffFn");
                          GlassOff();
                          Glass(fn);
                      });
            return glass;
        }

        [AlternateSignature]
        public static extern void GlassOff();

        /// <summary>
        /// Turns off the glass firing the click function unless noClick=true
        /// </summary>
        /// <param name="noClick">if set to <c>true</c> don't fire the click function.</param>
        public static void GlassOff(bool noClick)
        {
            jQueryObject glass = jQuery.Select("body > .VirtualGlass");
            if (glass.Length > 0)
            {
                glass.Each(
                    delegate(int i, Element domEl)
                    {
                        jQueryObject ths = jQuery.FromElement(domEl);
                        Action clickFn = (Action) ths.GetDataValue("GlassOffFn");
                        if (!noClick && clickFn != null)
                            clickFn();
                        if (!(bool) ths.GetDataValue("GlassStay"))
                        {
                            jQuery.Window.Unbind(".Glass");
                            ths.RemoveData("GlassOffFn");
                            ths.RemoveData("GlassStay");
                            ths.Remove();
                        }
                    });
            }
        }

        [AlternateSignature]
        public static extern void GlassStay();

        public static void GlassStay(bool stay)
        {
            stay = Arguments.Length <= 0 || stay;
            jQueryObject glass = jQuery.Select("body > .VirtualGlass");
            if (glass.Length > 0)
            {
                glass.Each(
                    delegate(int i, Element domEl)
                    {
                        jQueryObject ths = jQuery.FromElement(domEl);
                        ths.Data("GlassStay", stay);
                    });
            }
        }

        [AlternateSignature]
        public static extern void FlashWindow();

        public static void FlashWindow(string color)
        {
            color = color ?? "rgba(255,255,0,.3)";
            const int fade = 40;
            jQuery.FromHtml("<div id='FlashGlass' class='HiderZee'/>")
                .AppendTo(Document.Body)
                .CSS(GlassCss(color))
                .Hide()
                .FadeIn(fade, delegate { jQuery.Select("#FlashGlass").FadeOut(fade, delegate { jQuery.Select("#FlashGlass").Remove(); }); })
                ;
        }
    }
}